/* input.c */

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#include "input.h"
#include "global_macros.h"

#define READ_MODE "rb"
#define DEFAULT_SIZE 256

static FILE *input_file;

static char *code_table[ANSI_COUNT];

static int current_size;

static int current_elements;

/**
 * Reads the symbol count from the compressed file header. Symbol count means
 * the count of the original non compressed symbols.
 * @return The total of uncompressed symbols.
 */
static int read_symbol_count();

/**
 * Reads the code table from the compressed file header.
 * @return The code table used for decompressing the file.
 */
static char **read_code_table();

/**
 * Reads the compressed source from the compressed file and stores it as is
 * in the given parameter string.
 * @param source - The compressed source is stored in this string.
 */
static void read_compressed_source(unsigned char **source);

/**
 * Check string size and allocate new memory if needed.
 * @param string - The string which is checked for resizing.
 * @return The new string which will be resized if needed.
 */
static char *check_array_size(char *string);

extern char *read_uncompressed_file(char *in_filename,
                                    int occurrence[ANSI_COUNT])
{

    int c = 0;
    char *result_string;
    current_size = DEFAULT_SIZE;
    current_elements = 0;
    

    result_string = malloc(current_size);
    ENSURE_ENOUGH_MEMORY(result_string, "read_uncompressed_file");

    input_file = fopen(in_filename, READ_MODE);
    CHECK_OPEN_FILE(input_file, "read_uncompressed_file");

    while (c != EOF)
    {
        c = fgetc(input_file);

        /* add last character to string */
        result_string[current_elements] = c;

        /* occurrence up */
        occurrence[c]++;

        /* check array size */
        result_string = check_array_size(result_string);

        current_elements++;
    }

    fclose(input_file);

    return result_string;
}

extern int read_compressed_file(char *in_filename, unsigned char **source,
                                char **code_table[])
{
    int symbol_count;

    input_file = fopen(in_filename, READ_MODE);
    CHECK_OPEN_FILE(input_file, "read_compressed_file");

    printf("reading symbol count\n");
    symbol_count = read_symbol_count();

    printf("reading code table\n");
    *code_table = read_code_table();

    printf("reading source\n");
    read_compressed_source(source);

    fclose(input_file);

    return symbol_count;
}

static int read_symbol_count()
{
    
    char c;
    char *count_string;

    current_size = DEFAULT_SIZE;
    current_elements = 0;

    count_string = calloc(current_size, sizeof(char));
    ENSURE_ENOUGH_MEMORY(count_string, "read_symbol_count");

    c = fgetc(input_file);

    /* get the firs digits */
    while (isdigit(c))
    {
        
        /* append to string */
        count_string[current_elements] = c;

        current_elements++;

        /* check array size */
        count_string = check_array_size(count_string);

        c = fgetc(input_file);
 
    }

    return atoi(count_string);
}

static char **read_code_table()
{
    unsigned char symbol;
    unsigned char code_piece;
    char code[ANSI_COUNT];
    char *code_copy;
    int i;

    symbol = fgetc(input_file);

    while (symbol != TABLE_END)
    {
        /* read code */
        code_piece = fgetc(input_file);
        for (i = 0; isdigit(code_piece); i++)
        {
            code[i] = code_piece;
            code_piece = fgetc(input_file);
        }
        /* end of this code */
        code[i] = 0;

        /* save code to table */
        code_copy = malloc(sizeof(code));
        ENSURE_ENOUGH_MEMORY(code_copy, "read_code_table");
        strcpy(code_copy, code);
        code_table[symbol] = code_copy;

        /* read next symbol */
        symbol = fgetc(input_file);
    }

    return code_table;

}

static void read_compressed_source(unsigned char **source)
{
    char c;
    unsigned char d_c;
    /* allocate memory for source */
    current_size = DEFAULT_SIZE;
    current_elements = 0;

    *source = calloc(current_size, sizeof(unsigned char));

    ENSURE_ENOUGH_MEMORY(*source, "read_compressed_source");

    c = fgetc(input_file);
    for (current_elements = 0; feof(input_file) == 0; current_elements++)
    {    
        d_c = c;
        (*source)[current_elements] = (unsigned char) c;

        /* check size */
        if (current_elements >= current_size)
        {
            current_size += DEFAULT_SIZE;
            *source = realloc(*source, current_size);
            ENSURE_ENOUGH_MEMORY(*source, "input.c");
        }

        c = fgetc(input_file);
    }


}

static char *check_array_size(char *string)
{
    if (current_elements >= current_size)
    {
        current_size += DEFAULT_SIZE;
        string = realloc(string, current_size);
        ENSURE_ENOUGH_MEMORY(string, "input.c");
    }
    return string;
}
